package com.kizuki.thread;

import org.junit.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 1. 保证可见性
 * 2. 非原子性
 * 3. 禁止指令重排序
 */
public class TestVolatile {

//    private static int testNum1 = 0;
    private volatile static int testNum1 = 0;

    // 这种卡死的测试要用psvm @Test主线程结束了程序就终止了
    public static void main(String[] args) {
        new Thread(()->{
            while(testNum1 == 0) { // 一直执行,主线程改变了不可见,volatile可以保证可见性

            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        testNum1 = 1;
        System.out.println(testNum1);
    }

    private volatile static int testNum2 = 0;

    @Test
    public void test2(){
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int i1 = 0; i1 < 1000; i1++) {
                    testNum2 ++; // 非原子性操作
                }
            }).start();
        }

        while(Thread.activeCount() > 2) { // 说明还有上面的线程在跑
            Thread.yield();
        }
        System.out.println(testNum2); // 结果小于20000
    }

    @Test
    public void fixTest2(){
        AtomicInteger atomicInteger = new AtomicInteger();
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int i1 = 0; i1 < 1000; i1++) {
                    atomicInteger.getAndIncrement(); // CAS
                }
            }).start();
        }

        while(Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(atomicInteger.get()); // 20000
    }

    /**
     * 禁止指令重排序
     * 源代码-->编译器优化的重排--> 指令并行也可能会重排--> 内存系统也会重排---> 执行
     * 单线程下是没问题的，多线程下可能会出现数据问题
     */

}

